# -*- coding: utf-8 -*-
# vim: ts=4

# Author: Juan José Fumero

#from yacf.Frontend.C99.c_lexer import CLexer
#from yacf.Frontend.C99.c_parser import CParser

from yacf.Frontend.GNU.plyparser import PLYParser, Coord, ParseError
from yacf.Frontend.GNU.gnu_lexer import GNULexer
from yacf.Frontend.GNU import gnu_ast
from yacf.Frontend.C99 import c99_ast as c_ast

### GNU Extensions
class GNUParser(PLYParser):
#    def __init__(
#            self, 
#            lex_optimize=False,
#            lextab='yacf.Frontend.GNU.lextab',
#            yacc_optimize=False,
#            yacctab='yacf.Frontend.GNU.yacctab',
#            yacc_debug=False,
#            lexer_class = GNULexer):
#
#        super(GNUParser, self).__init__(lex_optimize, lextab, yacc_optimize, yacctab, yacc_debug, lexer_class = GNULexer)
#
   
    def p_init_declarator_1(self, p):
        """ init_declarator : declarator gnu_attribute_declaration_list
                            | declarator gnu_attribute_declaration_list EQUALS initializer
        """
        p[0] = (p[1], p[4] if len(p) > 3 else None)        

    def p_declarator_3(self, p):
        """ declarator  : gnu_attribute_declaration_list direct_declarator 
        """
        p[0] = p[1]
    
    def p_declarator_4(self, p):
        """ declarator  : gnu_attribute_declaration_list pointer direct_declarator 
        """
        p[0] = self._type_modify_decl(p[2], p[1])

#    def p_declarator_3(self, p):
#        """ declarator  : gnu_attribute_declaration_list reference direct_declarator 
#        """
#        p[0] = self._type_modify_decl(p[2], p[1])


    def p_struct_or_union_2(self, p):
        """ struct_or_union : STRUCT gnu_attribute_declaration_list 
                            | UNION gnu_attribute_declaration_list 
        """
        p[0] = p[1]

    def p_gnu_attribute_declaration_list(self, p):
        """ gnu_attribute_declaration_list : gnu_attribute
                                           | gnu_attribute_declaration_list gnu_attribute
        """
        if len(p) == 3:
            p[0] = p[1] + p[2]
        else:
            p[0] = p[1]

    def p_gnu_attribute(self, p):
        """ gnu_attribute : GNU_ATTRIBUTE LPAREN LPAREN gnu_attribute_list RPAREN RPAREN
                          | GNU_ATTRIBUTE LPAREN LPAREN  RPAREN RPAREN
        """
#        print " GNU ATTRIBUTE SILENTLY IGNORED "
#        p[0] = c_ast.Constant(type = 'int', value = '0')
        if len(p) == 7:
            p[0] = [p[4]]
        else:
            p[0] = [gnu_ast.GNUAttribute(word = "", parameters = [])]

    
    def p_gnu_attribute_list(self, p):
        """ gnu_attribute_list : gnu_attribute_value
                                  | gnu_attribute_list COMMA gnu_attribute_value 
        """
        if len(p) == 3:
            p[0] = gnu_ast.GNUAttribute(word = p[2], parameters = p[1])
        else:
            p[0] = gnu_ast.GNUAttribute(word = p[1], parameters = None)

    def p_gnu_attribute_value(self, p):
        """ gnu_attribute_value : identifier
                                   | identifier LPAREN expression RPAREN
                                   | identifier LPAREN identifier RPAREN
                                   | CONST 
        """
#        print " Attribute value "
        p[0] = c_ast.Constant(type = 'string', value = p[1])

    # GNU Extensions allows statements inside expressions (for whatever reason)
    def p_primary_expression_5(self, p):
        """ primary_expression  : LPAREN compound_statement RPAREN """
        p[0] = p[2]

    # Gnu builtins
    def p_primary_expression_6(self, p):
        """ primary_expression  : BUILTIN_VA_ARG LPAREN assignment_expression COMMA identifier RPAREN
                | BUILTIN_OFFSETOF LPAREN identifier COMMA offsetof_member_designator RPAREN
        """
        p[0] = c_ast.Constant(type = 'int', value = '')

    def p_offsetof_member_designator(self, p):
        """ offsetof_member_designator : identifier
                                       | offsetof_member_designator "." identifier
                                       | offsetof_member_designator "[" expression "]"
        """
        p[0] = c_ast.Constant(type = 'int', value = '')


    def p_type_specifier_2(self, p):
        """ type_specifier  : BUILTIN_VA_LIST
                            | BUILTIN_VA_ARG
        """
        if (len(p) == 2):
            p[0] = p[1]
        elif (len(p) == 3):
            p[0] = p[1] + p[2]
        elif (len(p) == 4):
            p[0] = p[1] + p[2] + p[3]


    def p_type_qualifier_1(self, p):
        """ type_qualifier  : GNU_RESTRICT
        """ 
        p[0] = p[1]

